# 电子记账情况汇总业务类
import os

import pandas as pd
import shutil

from PySide2.QtWidgets import QMessageBox
from openpyxl import load_workbook

from tools.Area_tools import Area_Tools


# import forms.res.other
class Ele_SituationService:
    def __init__(self, pre_month_path, now_month_path, now_review_path, community_path, out_path, is_audit_data=True):
        """
        初始化电子记账业务类
        :param pre_month_path: 前月记账概览路径
        :param now_month_path: 当前记账概览路径
        :param now_review_path: 当月账页复核路径
        :param community_path: 当季度小区样本路径
        :param out_path: 输出位置
        """
        self.is_audit_data = is_audit_data
        self.pre_month = pd.read_csv(pre_month_path, encoding='gbk')
        self.now_month = pd.read_csv(now_month_path, encoding='gbk')
        self.now_review = pd.read_csv(now_review_path, encoding='gbk')
        self.community = pd.read_csv(community_path, encoding='gbk', skiprows=[1])
        self.out_path = out_path
        # 将城乡标识拼接到当月记账概览中
        ## 获取当月记账概览的小区id
        self.now_month["小区ID"] = self.now_month["住户ID"].str[0:15].astype("int64")
        ## 拼接城乡标识   1    城镇     2   农村
        self.now_month = pd.merge(self.now_month, self.community[["VID调查小区ID", "LEVEL2城乡类别"]], how="inner",
                                  left_on="小区ID", right_on="VID调查小区ID")

        # 格式化账页复核的日期
        self.now_review['创建时间'] = self.now_review['创建时间'].astype('datetime64[ns]')
        self.now_review['记账日期'] = self.now_review['记账日期'].astype('datetime64[ns]')
        self.now_review['记账时间差'] = (
            (self.now_review['创建时间'] - self.now_review['记账日期']).dt.days).abs()
        # 生成账页复核的区县码
        self.now_review['COUN'] = self.now_review['SID'].str[0:6]

        # 共同户记账笔数差
        self.comonHouses = pd.merge(self.now_month,
                                    self.pre_month[['住户ID', '记账条数']].rename(
                                        columns={'记账条数': '前月记账条数'}),
                                    how='inner', on=['住户ID'])
        self.comonHouses["记账笔数差"] = (self.comonHouses['记账条数'] - self.comonHouses['前月记账条数']).abs()

        # 获取电子记账的月份
        self.month = int(now_review_path[now_review_path.find('5105.') + 9:now_review_path.find('-')])
        # 当前月 电子记账的月份 导出月份
        self.preMonth = (self.month + 1) % 12
        # 获取导出的日历
        self.calada = now_review_path[now_review_path.find('-') + 1:len(now_review_path) - 4][7:15]

    def getElecAccountSituation(self, accoutOverView, comonHouses, accoutReview):
        """
        获取区县电子所有电子记账情况
        :param accoutOverView: 账页概览数据表
        :param comonHouses: 账页概览, 共同户表(包含记账笔数)
        :param accoutReview: 账页复核
        :return: 每个区县的记账项目数据
        """
        res = []
        elecDataDf = accoutOverView[
            (accoutOverView['是否电子记账户'] == '是') & (accoutOverView['激活状态'] == '已激活')].copy()
        accoutOverViewCit = elecDataDf[elecDataDf['LEVEL2城乡类别'].isin(['1'])].copy()
        accoutOverViewCout = elecDataDf[elecDataDf['LEVEL2城乡类别'].isin(['2'])].copy()
        accoutReviewEle = accoutReview[accoutReview['记账方式'] == '移动'].copy()
        # 样本量
        ## 全体
        res.append(accoutOverView.shape[0])
        ## 城镇
        res.append(accoutOverView[accoutOverView['LEVEL2城乡类别'].isin(['1'])].shape[0])
        ## 农村
        res.append(accoutOverView[accoutOverView['LEVEL2城乡类别'].isin(['2'])].shape[0])

        # 电子记账激活使用情况
        ## 全体
        res.append(elecDataDf.shape[0])
        ## 城镇
        res.append(accoutOverViewCit.shape[0])
        ## 农村
        res.append(accoutOverViewCout.shape[0])
        ## 全体电子记账率（%）
        res.append(res[3] / res[0] * 100)
        ## 城镇电子记账率（%）
        res.append(res[4] / res[1] * 100)
        ## 农村电子记账率（%）
        res.append(res[5] / res[2] * 100)

        # 电子记账达标户情况
        ## 全体
        ## 城镇数量
        citNum = accoutOverViewCit[
            (accoutOverViewCit["记账条数"].astype(int) >= 40) & (accoutOverViewCit["未记天数"].astype(int) <= 8) & (
                    accoutOverViewCit["连续未记天数"].astype(int) <= 3)].shape[0]
        ## 农村数量
        conNum = accoutOverViewCout[
            (accoutOverViewCout["记账条数"].astype(int) >= 40) & (accoutOverViewCout["未记天数"].astype(int) <= 10) & (
                    accoutOverViewCout["连续未记天数"].astype(int) <= 5)].shape[0]
        ## 全体
        res.append(citNum + conNum)
        ## 城镇
        res.append(citNum)
        ## 农村
        res.append(conNum)
        ## 全体电子记账达标率（%）
        res.append(res[9] / res[3] * 100)
        ## 城镇电子记账户达标率（%）
        res.append(res[10] / res[4] * 100)
        ## 农村电子记账达标率（%）
        res.append(res[11] / res[5] * 100)

        # 未记账天数超过10天以上的户
        ## 户数
        res.append(elecDataDf[elecDataDf['未记天数'].astype(int) > 10].shape[0])
        ## 占比（%）
        res.append(res[15] / res[3] * 100)

        # 记账笔数少于40笔的户
        ## 户数
        res.append(elecDataDf[elecDataDf['记账条数'] < 40].shape[0])
        res.append(res[17] / res[3] * 100)

        # 户均记账天数情况
        ## 全体户均未记账天数
        res.append(elecDataDf['未记天数'].astype(float).sum() / res[3])
        ## 城镇户均未记账天数
        res.append(accoutOverViewCit['未记天数'].astype(float).sum() / res[4])
        ## 农村户均未记账天数
        res.append(accoutOverViewCout['未记天数'].astype(float).sum() / res[5])
        ## 全体户均连续未记账天数
        res.append(elecDataDf['连续未记天数'].astype(float).sum() / res[3])
        ## 城镇户均连续未记账天数
        res.append(accoutOverViewCit['连续未记天数'].astype(float).sum() / res[4])
        ## 农村户均连续未记账天数
        res.append(accoutOverViewCout['连续未记天数'].astype(float).sum() / res[5])

        # 记账笔数
        ## 全体户均记账笔数
        res.append(elecDataDf['记账条数'].astype(float).sum() / res[3])
        ## 城镇户均记账笔数
        res.append(accoutOverViewCit['记账条数'].astype(float).sum() / res[4])
        ## 农村户均记账笔数
        res.append(accoutOverViewCout['记账条数'].astype(float).sum() / res[5])

        # 月度间记账笔数相差50笔
        ## 全体
        res.append(comonHouses[comonHouses['记账笔数差'] > 50].shape[0])
        ## 城镇
        res.append(
            comonHouses[(comonHouses['LEVEL2城乡类别'].isin(['1'])) & (comonHouses['记账笔数差'] > 50)].shape[0])
        ## 农村
        res.append(comonHouses[(comonHouses['LEVEL2城乡类别'].isin(['2'])) & (comonHouses['记账笔数差'] > 50)].shape[0])

        # 支收比
        ## 总支收比
        res.append(elecDataDf['支出合计'].sum() / elecDataDf['收入合计'].sum())
        ## 支收比大于1的户数 Nan 是分子 分母都为0
        elecDataDf['支收比'] = elecDataDf['支出合计'] / elecDataDf['收入合计']
        res.append(elecDataDf[(elecDataDf['支收比'] > 1) | elecDataDf['支收比'].isna()].shape[0])
        ## 占比
        res.append(res[32] / res[3] * 100)

        # 补记情况
        ## 15天的电子记账所有数据
        day15Df = accoutReviewEle[
            (accoutReviewEle['记账日期'].dt.month == self.month) & (accoutReviewEle['记账时间差'] > 15)]
        ## 补记前月的电子记账所有数据
        addtionDf = accoutReviewEle[
            (accoutReviewEle['记账日期'].dt.month == self.month) & (
                    accoutReviewEle['创建时间'].dt.month == (self.month + 1) % 12)]
        ## 3月记账时间与创建时间相差15天笔数
        res.append(day15Df.shape[0])
        ## 4月补记3月账目笔数
        res.append(addtionDf.shape[0])
        ## 3月记账时间与创建时间相差15天户数、
        res.append(day15Df.drop_duplicates(subset=['SID']).shape[0])
        ## 4月补记3月账目户数
        res.append(addtionDf.drop_duplicates(subset=['SID']).shape[0])
        return res

    def get_account_num_overxx(self, num=50):
        """
        记账笔数 > 50
        :return:
        """
        return self.comonHouses[self.comonHouses["记账笔数差"] > num][
            ["住户ID", "COUN", "记账户", "前月记账条数", "记账条数", "记账笔数差"]]

    def get_out_in_overxx(self, num=1):
        """
        收支比>1
        :return:
        """
        temp = self.now_month.copy()
        temp["支收比"] = temp["支出合计"] / temp["收入合计"]
        return temp[temp["支收比"] > num][["住户ID", "COUN", "记账户", "支出合计", "收入合计", "支收比"]]

    def get_account_addition_15(self):
        """
        相差15天补记的户
        :return:
        """
        ## 15天的电子记账所有数据
        day15Df = self.now_review[
            (self.now_review['记账日期'].dt.month == self.month) & (self.now_review['记账时间差'] > 15)].copy()
        return day15Df.drop_duplicates(subset=['SID'])[["SID", "COUN", "scode", "户主"]]

    def to_EleExcel(self, datas):
        """
        输出到excel中
        :param datas: 组装数据的二维数组
        :return:
        """
        fielName = self.calada[0:4] + '电子记账汇总.xlsx'
        # fullPath = './res/电子记账汇总/' + fielName
        fullPath = self.out_path + r"/" + fielName
        if not os.path.exists(fullPath):
            # 不存在拷贝模板
            shutil.copyfile('./res/电子记账访户初始化数据/模板.xlsx', fullPath)

        # 加载数据
        mbwb = load_workbook(fullPath)
        # 获取所有的sheet，是否包含已经执行过得sheet
        if not str(self.month) + '月' in mbwb.sheetnames:
            # 获取模板sheet
            mbSheet = mbwb.copy_worksheet(mbwb['模板'])

            # 组装导出时间
            suppData = str(int(self.calada[4:6])) + '.' + str(int(self.calada[6:9]))
            # 数据值
            sheetTitleText = '全市' + str(self.month) + '月电子记账汇总情况表'
            suppInfoText = '补记情况（' + suppData + '导出）'
            preMonthDayText = str(self.month) + '月记账时间与创建时间相差15天笔数'
            preMonthHouseText = str(self.month) + '月记账时间与创建时间相差15天户数'
            nowMonthCountText = '' + str(self.preMonth) + '月补记' + str(self.month) + '月账目笔数'
            nowMonthCountHoueText = '' + str(self.preMonth) + '月补记' + str(self.month) + '月账目户数'

            # 设置值
            mbSheet.title = str(self.month) + '月'
            mbSheet.cell(1, 2).value = sheetTitleText
            mbSheet.cell(3, 36).value = suppInfoText
            mbSheet.cell(4, 36).value = preMonthDayText
            mbSheet.cell(4, 37).value = nowMonthCountText
            mbSheet.cell(4, 38).value = preMonthHouseText
            mbSheet.cell(4, 39).value = nowMonthCountHoueText

            # 写数据
            i = 5
            for data in datas:
                for j in range(len(data)):
                    mbSheet.cell(i, j + 2).value = data[j]
                i = i + 1
            # 保存
            mbwb.save(fullPath)
            mbwb.close()

            # 是否添加审核数据
            if self.is_audit_data:
                with pd.ExcelWriter(fullPath,mode="a") as writer:
                    self.get_account_num_overxx().to_excel(writer, sheet_name="相差50笔以上得户", index=False)
                    self.get_out_in_overxx().to_excel(writer, sheet_name="支收比大于1的户", index=False)
                    self.get_account_addition_15().to_excel(writer, sheet_name="相差15天补记的户", index=False)


        else:
            return

    def initData(self):

        # 判断目录是否存在

        # if not os.path.exists("./结果输出/电子记账汇总"):
        #     os.makedirs("./结果输出/电子记账汇总")

        # 遍历所有区县 获取二维数组数据
        datas = []
        for area in Area_Tools.area_objs:
            if (area['No'] == 510500):
                datas.append(self.getElecAccountSituation(self.now_month, self.comonHouses, self.now_review))
            else:
                datas.append(
                    self.getElecAccountSituation(self.now_month[self.now_month['COUN'] == area['No']],
                                                 self.comonHouses[self.comonHouses['COUN'] == area['No']],
                                                 self.now_review[self.now_review['COUN'] == str(area['No'])]))
        self.to_EleExcel(datas)
        QMessageBox.information(None, '提示', '执行完成')


